package com.t3.fx
{
	import com.t3.client.T3Client;
	import com.t3.display.StageObject;
	import com.t3.events.*;
	import com.t3.tuio.TUIOCursor;
	import com.t3.tuio.TUIOEvent;
	import flash.utils.IExternalizable;
	import flash.utils.IDataInput;
	import flash.utils.IDataOutput;
	import flash.net.registerClassAlias;
	
	import flash.display.DisplayObject;
	import flash.display.Sprite;
	import flash.geom.Point;
	import flash.geom.Rectangle;
	
	import gs.TweenMax;

	public class DraggableObject extends StageObject implements IExternalizable
	{
		private static var IDS:uint = 0;
		
		protected var _cursor:TUIOCursor;
		protected var _dx:int;
		protected var _dy:int;
		protected var _color:Number;
		protected var _alpha:Number;
		protected var _bounds:Rectangle;
		protected var _dragState:DragState;
		protected var _id:uint = IDS++;
		protected var _hto:Sprite = new Sprite();
		protected var _isClone:Boolean = false;
		
		public function DraggableObject( bounds:Rectangle, color:Number = 0xFFFFFF, alpha:Number = 1, isClone:Boolean = false ):void
		{	
			registerClassAlias( "import com.t3.fx.DraggableObject", DraggableObject );
			this.x = bounds.x;
			this.y = bounds.y;
			
			_alpha = alpha;
			_color = color;
			_bounds = bounds;
			_isClone = isClone;
			
			repaint();
			
			_dragState = new DragState( this );
		}
		
		public function clone():DraggableObject
		{
			var dob:DraggableObject = new DraggableObject( _bounds, _color, _alpha, true );
			dob.stageLoc = this.stageLoc;
			
			return dob;
		}
		
		protected function repaint():void
		{
			_hto.graphics.clear();
			_hto.graphics.beginFill( _color, _alpha );
			_hto.graphics.drawRect( 0, 0, _bounds.width, _bounds.height );
			_hto.graphics.endFill();
			
			addChild( _hto );
			
			this.hitArea = _hto;
		}
		
		public function startDragging( cursor:TUIOCursor ):DraggableObject
		{			
			this.alpha = 0.7;
			this._cursor = cursor;
			
			this._dx = ( cursor.xpos * T3Client._width ) - this.stageX;
			this._dy = ( cursor.ypos * T3Client._height ) - this.stageY;
			
			_dragState.xOrigin = this.stageX;
			_dragState.yOrigin = this.stageY;
			
			cursor.addEventListener( TUIOEvent.CURSOR_MOVED, this.dragHandler );
			cursor.addEventListener( TUIOEvent.REMOVE_TUIO_CUR, stopDragging );
			
			this.addChild( _dragState );
			
			return this;
		}
		
		public function stopDragging( event:TUIOEvent ):void
		{	
			this.alpha = 1;		
			this._cursor.removeEventListener( TUIOEvent.CURSOR_MOVED, dragHandler );
			this._cursor.removeEventListener( TUIOEvent.REMOVE_TUIO_CUR, stopDragging );
			
			this.removeChild( this._dragState );
			this._cursor = null;
			
			if( _dragState.dropArea == null )
			{
				toOrigin( true );					
			}
			else
			{
				_dragState.dropOrigin = _dragState.dropArea;
			}
			
			this.dispatchEvent( new DragEvent( DragEvent.OBJECT_DROPPED, _dragState.dropOrigin ) );
		}
		
		public function snapTo( xpos:uint, ypos:uint ):void
		{
			toPoint( true, xpos, ypos );
		}
		
		protected function toOrigin( animate:Boolean ):void
		{
			toPoint( animate, _dragState.xOrigin, _dragState.yOrigin );
		}
		
		protected function toPoint( animate:Boolean, stageX:int, stageY:int ):void
		{
			var point:Point = new Point( this.x + ( stageX-this.stageX ), this.y + ( stageY-this.stageY ) );
			
			if( animate )
			{
				var tween:TweenMax = TweenMax.to( this, 0.5, { x:point.x, y:point.y, onComplete:snapComplete } );
			}
			else
			{
				this.stageLoc = new Point( stageX, stageY );
			}
		}
		
		protected function snapComplete():void
		{
			this.dispatchEvent( new AnimationEvent( AnimationEvent.ANIMATION_FINISH ) );
		}
		
		public function get dragState():DragState
		{
			return _dragState;
		}
		
		protected function dragHandler( event:TUIOEvent ):void
		{
			this.stageLoc = new Point( event.xStage - _dx, event.yStage - _dy );

			this.dispatchEvent( new DragEvent( DragEvent.OBJECT_MOVED, _dragState.dropArea ) );
		}
		
		public function set cursor( curs:TUIOCursor ) : void 
		{
			this._cursor = curs;
		}
		
		public function get cursor():TUIOCursor
		{
			return _cursor;
		}
		
		public function get id():uint
		{
			return _id;
		}
		
		public function get hitObject():DisplayObject
		{
			return _hto;
		}
		
		public override function writeExternal(output:IDataOutput):void 
		{
			super.writeExternal(output);
		}

		public override function readExternal(input:IDataInput):void
		{
			super.readExternal(input);
		}
	}
}